import os
import socket
import time


class MyServer:
    def __init__(self):
        self.host = '127.0.0.1'  # 本地地址
        self.port = 2121  # 端口号

    def start_server(self,client):
        print("开放端口为：", self.port)  # 打印端口和路径信息
        server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # 创建socket对象
        server_socket.bind((self.host, self.port))  # 绑定主机和端口
        server_socket.listen()  # 监听连接

        while True:
            print("等待连接...")
            client_socket, addr = server_socket.accept()  # 接受客户端连接
            print(f'已接收到来自{addr}的连接',time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
            client.handle_client(client_socket, addr)  # 处理客户端请求
            print('结束连接')

class OnesClient:
    def __init__(self, base_path='F:/', data_size=1024 * 1024):
        self.base_path = base_path  # 映射地址

        self.data_size = data_size  # 发送的数据大小
        self.data = None  # 发送文件的数据
        self.FolderMessage = None  # 文件夹信息
        self.FileMessage = None  # 文件信息

        self.IsCommand = None  # 是命令的标志位
        self.IsFolder = None  # 是文件夹的标志位

    # 处理一个客户端的请求
    def handle_client(self, client_socket, addr):
        self.FolderMessage = self.GetFolderMessage(self.base_path)  # 初始化文件夹信息
        print('初始化文件夹成功')
        while True:
            try:#防止客户端断开连接时整个服务器退出
                response = client_socket.recv(self.data_size).decode('gbk')  # 接收客户端的响应
                print("接收到客户端请求",response,type(response))
                if response == '':
                    break
            except Exception as e:
                print(e)
                break
            response, self.IsCommand = self.AnalysisClient(response)  # 解析客户端的请求
            print("解析客户端需求完成")
            if self.IsCommand:  # 是命令
                if response == "ls":  # 如果客户端请求列出文件和文件夹
                    self.DoLs(client_socket, self.FolderMessage)
                elif response == "../":  # 如果客户端请求切换到上一级目录
                    self.DoUp()# 切换到上一级目录
                    self.FolderMessage = self.GetFolderMessage(self.base_path)  # 更新文件夹信息
                    self.DoLs(client_socket, self.FolderMessage)  # 列出文件夹内容
                elif response == "pwd":  # 如果客户端请求打印当前路径
                    self.DoPwd(client_socket, self.base_path, self.data_size, addr)
                elif response == "wq":  # 如果客户端请求退出
                    self.DoWq(client_socket, self.base_path, self.data_size, addr)
                    client_socket.close()  # 关闭客户端连接
                    break
            else:  # 是选择的数字
                self.FileMessage = self.GetFileMessage(response, self.FolderMessage)  # 获得文件信息
                self.IsFolder = self.DoIsFolder(response)  # 判断是文件夹
                if self.IsFolder:  # 是文件夹
                    self.DoCd(response)  # 进入文件夹
                    self.FolderMessage = self.GetFolderMessage(self.base_path)  # 更新文件夹信息
                    self.DoLs(client_socket, self.FolderMessage)  # 列出文件夹内容
                    print("进入文件夹",self.base_path)
                else:  # 是文件
                    print("文件开始发送")
                    self.SendFile(client_socket, self.FileMessage, self.data_size)  # 发送文件给客户端

    # 解析客户端的请求,是命令还是选择文件或文件夹
    def AnalysisClient(self, response):
        try:
            response = int(response)  # 尝试将响应转换为整数索引
            return response, False  # 如果是数字返回False
        except ValueError:
            return response, True  # 如果是命令返回True
        pass

    # 处理ls指令
    def DoLs(self, client_socket, FolderMessage):
        #print(f'client_socket: {client_socket},FolderMessage: {FolderMessage}')
        data=str(FolderMessage)
        client_socket.sendall(data.encode('gbk'))
        print('发送文件夹数据完成')

    # 处理cd指令
    def DoCd(self,response):
        self.base_path = os.path.join(self.base_path, self.FolderMessage[response][0])


    # 处理pwd指令
    def DoPwd(self, client_socket, base_path, data_size, addr):
        pass

    # 处理wq指令
    def DoWq(self, client_socket, base_path, data_size, addr):
        pass

    # 处理返回上级指令
    def DoUp(self):
        self.base_path = os.path.dirname(self.base_path)
        pass

    # 处理选择的数字
    def DoSelect(self, client_socket, base_path, data_size, addr):
        pass

    # 判断是否为文件夹
    def DoIsFolder(self, response):
        name = self.FolderMessage[response][0]
        path = os.path.join(self.base_path, name)
        return os.path.isdir(path)

    # 发送文件
    def SendFile(self, client_socket, file_path, data_size):
        data=[('wj',0),(file_path[0][0],file_path[0][1])]
        client_socket.sendall(str(data).encode('gbk'))
        with open(file_path[0][0], 'rb') as f:
            while True:
                data = f.read(data_size)
                if not data:
                    break
                client_socket.sendall(data)
        print("发送文件完成")

    # 获取文件夹信息
    def GetFolderMessage(self, base_path):
        # 数据结构：[('folder1', 3072), ('file1.txt', 1024)]绝对路径
        folder_info = []
        for name in os.listdir(base_path):
            file_path=os.path.join(base_path,name)
            path = os.path.join(base_path, name)
            file_size = self.GetSize(file_path)
            folder_info.append((file_path, file_size))
        #print(f'folder_info: {folder_info}')
        return folder_info

    # 获取文件信息
    def GetFileMessage(self, response, FolderMessage):
        # 数据结构：[('file2.txt', 2048)]
        file_info = []
        file_path = FolderMessage[response][0]
        file_size = self.GetSize(file_path)
        file_info.append((file_path, file_size))
        return file_info

    # 获取大小（文件夹大小为空）
    def GetSize(self, path):
        total_size = 0
        if os.path.isfile(path):  # 如果是文件
            total_size = os.path.getsize(path)
        elif os.path.isdir(path):  # 如果是文件夹
            total_size = 0
        return total_size


if __name__ == '__main__':
    server = MyServer()
    client = OnesClient()
    server.start_server(client)
